import { _decorator, Animation, BoxCollider, Camera, CapsuleCollider, Color, Component, director, EventTouch, find, game, geometry, Gradient, instantiate, JsonAsset, Label, Layers, Line, log, Material, math, MeshRenderer, Node, PhysicsSystem, Prefab, RenderTexture, resources, RigidBody, SkeletalAnimation, SkinnedMeshRenderer, SkyboxInfo, Sprite, SpriteAtlas, SpriteFrame, SpriteRenderer, sys, Tween, tween, UIOpacity, v2, v3, Vec2, Vec3, WorldNode3DToLocalNodeUI } from 'cc';
import { Card } from '../Card';
import { PlayerController } from './PlayerController';
import { Player } from '../Player';
import { Monster } from '../Monster';
import { ZTool } from './ZTool';
import { UIManager } from './UIManager';
import Banner from './Banner';
const { ccclass, property } = _decorator;

export enum Group {
    Default = Math.pow(2, 0),
    Player = Math.pow(2, 1),
    Monster = Math.pow(2, 2),
    Money = Math.pow(2, 3),
    Card = Math.pow(2, 4),
    CardBase = Math.pow(2, 5),
}

@ccclass('GameManager')
export class GameManager extends Component {

    private static _instance: GameManager = null;
    public static get Instance(): GameManager {
        if (!this._instance) {
            this._instance = new GameManager();
        }
        return this._instance;
    }


    @property({ type: Node })
    MonsterInit: Node = null;
    @property({ type: Node })
    MainCamera: Node = null;
    @property({ type: Node })
    PlayerInit: Node = null;

    @property({ type: JsonAsset })
    MonsterData: JsonAsset = null;
    @property({ type: JsonAsset })
    LevelData: JsonAsset = null;

    IsStart: boolean = false;//游戏开始
    IsEnterFight: boolean = false;//进入战斗区域
    IsRunToArea: boolean = false;
    MoneyNum: number = 0;
    IsShaking: boolean = false;

    CardBaseColor = new Color(71, 202, 202);
    CardSetNum: number = 0;

    EnemyDeadNum: number = 0;
    PlayerDeadNum: number = 0;
    PlayerID: number = 0;

    EnemyMonsters = [];
    PlayerMonsters = [];
    CanStart: boolean = false;

    Level: Node = null;
    FinishEnv: Node = null;
    EndArea: Node = null;
    RoadInit: Node = null;
    onLoad() {
        GameManager._instance = this;
        for (let i = 0; i < 15; i++) {
            find("Level" + i).active = false;
        }
        this.Level = find("Level" + this.GetLocalStorage("Level"));
        this.Level.active = true;
        this.RoadInit = this.Level.getChildByName("RoadInit");
        this.InitCardAndMoney();
        this.InitEndArea();
        find("Canvas/LevelNum").getComponentInChildren(Label).string = (this.GetLocalStorage("LevelTitle") + 1) + " 关";
        resources.load("Prefabs/Player/Player" + this.GetLocalStorage("Role"), Prefab, (err, pre) => {
            let player = instantiate(pre);
            PlayerController.Instance.PlayerScript = player.getComponent(Player);
            player.setParent(this.PlayerInit);
            this.scheduleOnce(() => {
                this.CanStart = true;
                UIManager.Instance.Main.children[0].active = true;
            }, 0.5)
        })
        if (this.GetLocalStorage("UnLockRole0") == 0) {
            this.SetLocalStorage("UnLockRole0", 1);
        }
    }

    start() {
        tween(director.getScene().globals.skybox)
            .to(200, { rotationAngle: 360 })
            .call(() => {
                director.getScene().globals.skybox.rotationAngle = 0;
            })
            .union()
            .repeatForever()
            .start();
        this.InitFinishEnv();
        Banner.Instance.ShowNativeAd();
        Banner.Instance.ShowBanner();
    }

    UpdatePlayerModel() {

    }

    InitEndArea() {//初始化对决场地
        let end = this.Level.getChildByName("End") ? this.Level.getChildByName("End") : this.RoadInit.getChildByName("End");
        if (this.GetLocalStorage("Level") < 5) {
            resources.load("Prefabs/End/EndArea1", Prefab, (err, pre) => {
                let area = instantiate(pre);
                area.setParent(end);
                this.EndArea = area;
            })
        }
        else {
            if (this.GetLocalStorage("Level") < 10) {
                resources.load("Prefabs/End/EndArea2", Prefab, (err, pre) => {
                    let area = instantiate(pre);
                    area.setParent(end);
                    this.EndArea = area;
                })
            }
            else {
                resources.load("Prefabs/End/EndArea3", Prefab, (err, pre) => {
                    let area = instantiate(pre);
                    area.setParent(end);
                    this.EndArea = area;
                })
            }
        }
    }

    InitCardAndMoney() {//初始化卡牌和钞票
        let cardInit = this.Level.getChildByName("CardInit") ? this.Level.getChildByName("CardInit") : this.RoadInit.getChildByName("CardInit");
        for (let i = 0; i < cardInit.children.length; i++) {
            resources.load("Prefabs/Card", Prefab, (err, pre) => {
                let card = instantiate(pre);
                card.setParent(cardInit.children[i]);
            })
        }
        let moneyInit = this.Level.getChildByName("MoneyInit") ? this.Level.getChildByName("MoneyInit") : this.RoadInit.getChildByName("MoneyInit");
        for (let i = 0; i < moneyInit.children.length; i++) {
            resources.load("Prefabs/Money", Prefab, (err, pre) => {
                let money = instantiate(pre);
                if (ZTool.getRandomIntWithMax(1, 100) <= 10) {
                    money.scale = v3(2, 2, 2);
                    money.setPosition(v3(0, 0.5, 0));
                }
                money.setParent(moneyInit.children[i]);
            })
        }
    }

    InitFinishEnv() {//初始化卡牌基座
        if (this.GetLocalStorage("Level") == 4 || this.GetLocalStorage("Level") == 9 || this.GetLocalStorage("Level") == 14) {
            resources.load("Prefabs/End/FinishEnvBoss", Prefab, (err, pre) => {
                let env = instantiate(pre);
                env.setParent(this.RoadInit.getChildByName("End"));
                this.FinishEnv = env;
            })
        }
        else {
            if (this.GetLocalStorage("Level") == 0) {
                resources.load("Prefabs/End/FinishEnv2v2", Prefab, (err, pre) => {
                    let env = instantiate(pre);
                    env.setParent(this.Level.getChildByName("End"));
                    this.FinishEnv = env;
                })
            }
            else {
                resources.load("Prefabs/End/FinishEnv3v3", Prefab, (err, pre) => {
                    let env = instantiate(pre);
                    env.setParent(this.Level.getChildByName("End"));
                    this.FinishEnv = env;
                })
            }
        }
    }

    update(dt: number) {

    }

    lateUpdate(dt: number) {

    }

    GetLocalStorage(key: string) {//初始化数据存储
        if (!sys.localStorage.getItem(key)) {
            sys.localStorage.setItem(key, "0");
        }
        return Number(sys.localStorage.getItem(key));
    }
    SetLocalStorage(key: string, value: number) {
        sys.localStorage.setItem(key, value.toString());
    }

    UpdateAllCardTop() {
        let cardInit = this.Level.getChildByName("CardInit") ? this.Level.getChildByName("CardInit") : this.RoadInit.getChildByName("CardInit");
        for (let i = 0; i < cardInit.children.length; i++) {
            cardInit.children[i].getComponentInChildren(Card).UpdateCardTop();
        }
    }

    Fight(playerMonster: Node, enemyMonster: Node) {
        playerMonster.getComponent(Monster).MonsterAni.crossFade("Run");
        enemyMonster.getComponent(Monster).MonsterAni.crossFade("Run");
        tween(playerMonster)
            .to(1, { worldPosition: playerMonster.getComponent(Monster).FightPoint })
            .call(() => {
                playerMonster.getComponent(Monster).MonsterAni.crossFade("Attack");
            })
            .start()
        tween(enemyMonster)
            .to(1, { worldPosition: enemyMonster.getComponent(Monster).FightPoint })
            .call(() => {
                enemyMonster.getComponent(Monster).MonsterAni.crossFade("Attack");
            })
            .start()
    }

    Shaking(Pos: Vec3, gap: number, randomMax: number) {
        this.IsShaking = true;
        tween(this.node)
            .delay(gap)
            .call(() => { Pos.set(ZTool.getRandom(-randomMax, randomMax), Pos.y + ZTool.getRandom(-randomMax, randomMax), Pos.z) })
            .union()
            .repeat(10)
            .call(() => {
                Pos.set(PlayerController.Instance.CameraPosed);
                this.IsShaking = false;
            })
            .start();
    }

    ShowEnemyFightCard(enemyIndex: number) {//对方展示战斗卡牌
        let Pos = this.FinishEnv.children[enemyIndex].getChildByName("CardBase2").getChildByName("Pos").getWorldPosition();
        resources.load("Prefabs/Card", Prefab, (err, pre) => {
            let card = instantiate(pre);
            card.setParent(find("EnemyFightInit"));
            card.getComponent(BoxCollider).enabled = false;
            card.getComponent(Card).CardTop.active = false;
            card.getComponent(Card).Name = this.LevelData.json[this.GetLocalStorage("Level")]["Enemy" + enemyIndex];
            card.getComponent(Card).CardBase = this.FinishEnv.children[enemyIndex].getChildByName("CardBase2");
            card.eulerAngles = v3(-90, 180, 0);
            card.setWorldPosition(v3(Pos.x, Pos.y, Pos.z - 1));
            tween(card)
                .to(1, { worldPosition: Pos }, { easing: "backOut" })
                .call(() => {
                    this.ShowCardPower(this.FinishEnv.children[enemyIndex].getChildByName("BattleRoad").getChildByName("EnemyPower"), card.getComponent(Card).PriceValue);
                    card.getComponent(Card).CardRole.active = false;
                    let name = card.getComponent(Card).Name;
                    if (card.getComponent(Card).Name.substring(0, 2) == "黄金") {
                        name = card.getComponent(Card).Name.substring(2, name.length);
                    }
                    resources.load("Prefabs/Monster/" + name, Prefab, (err, pre) => {
                        let monster = instantiate(pre);
                        monster.setParent(GameManager.Instance.MonsterInit);
                        monster.getComponent(Monster).MonsterAni.crossFade("Jump");
                        monster.getComponent(Monster).IsEnmey = true;
                        monster.getComponent(Monster).Name = card.getComponent(Card).Name;
                        if (card.getComponent(Card).Name.substring(0, 2) == "黄金") {
                            resources.load("Materials/Golden", Material, (err, mat) => {
                                monster.getChildByName("Model").getComponentInChildren(SkinnedMeshRenderer).setMaterialInstance(mat, 0);
                            })
                        }
                        monster.getComponent(Monster).PowerValue = card.getComponent(Card).PriceValue;
                        monster.getComponent(Monster).FightPoint = this.FinishEnv.children[enemyIndex].getChildByName("FightPoint").getWorldPosition();
                        monster.eulerAngles = v3(0, 180, 0);
                        monster.setPosition(Pos);
                        this.EnemyMonsters.push(monster);
                    })
                })
                .start()
        })
    }

    ShowBossFightCard() {//对方展示Boss战斗卡牌
        log("对方展示Boss战斗卡牌")
        let Pos = this.FinishEnv.getChildByName("CardBaseBoss").getChildByName("Pos").getWorldPosition();
        resources.load("Prefabs/Card", Prefab, (err, pre) => {
            let card = instantiate(pre);
            card.setParent(find("EnemyFightInit"));
            card.getComponent(BoxCollider).enabled = false;
            card.getComponent(Card).IsBoss = true;
            card.getComponent(Card).CardTop.active = false;
            card.getComponent(Card).Name = this.LevelData.json[this.GetLocalStorage("Level")]["Boss"];
            card.getComponent(Card).CardBase = this.FinishEnv.getChildByName("CardBaseBoss")
            card.eulerAngles = v3(-90, 180, 0);
            card.scale = v3(2.5, 2.5, 2.5);
            card.setWorldPosition(v3(Pos.x, Pos.y, Pos.z - 1));
            tween(card)
                .to(1, { worldPosition: Pos }, { easing: "backOut" })
                .call(() => {
                    this.ShowCardPower(this.FinishEnv.getChildByName("CardBaseBoss").getChildByName("EnemyPower"), card.getComponent(Card).PriceValue);
                    card.getComponent(Card).CardRole.active = false;
                    resources.load("Prefabs/Monster/" + card.getComponent(Card).Name, Prefab, (err, pre) => {
                        let monster = instantiate(pre);
                        monster.setParent(GameManager.Instance.MonsterInit);
                        monster.getComponent(Monster).MonsterAni.crossFade("Jump");
                        monster.getComponent(Monster).IsEnmey = true;
                        monster.getComponent(Monster).Name = card.getComponent(Card).Name;
                        monster.getComponent(Monster).PowerValue = card.getComponent(Card).PriceValue;
                        monster.getComponent(Monster).FightPoint = this.FinishEnv.getChildByName("CardBaseBoss").getChildByName("FightPoint").getWorldPosition();
                        monster.eulerAngles = v3(0, 180, 0);
                        monster.scale = v3(2.5, 2.5, 2.5);
                        monster.setPosition(Pos);
                        this.EnemyMonsters.push(monster);
                    })
                })
                .start()
        })
    }

    ShowCardPower(power: Node, price: number) {//展示卡牌战斗力
        if (this.GetLocalStorage("Level") == 4 || this.GetLocalStorage("Level") == 9 || this.GetLocalStorage("Level") == 14) {
            power.destroyAllChildren();
        }
        for (let i = 0; i < price.toString().length; i++) {
            let powerNd = new Node();
            powerNd.setParent(power);
            switch (price.toString().length) {
                case 2:
                    {
                        powerNd.setPosition(-0.15 + i * 0.3, 0);
                    }
                    break;
                case 3:
                    {
                        powerNd.setPosition(-0.3 + i * 0.3, 0);
                    }
                    break;
            }
            powerNd.addComponent(SpriteRenderer);
            let material = power.parent.getChildByName("VS").getComponent(SpriteRenderer).getMaterial(0);
            powerNd.getComponent(SpriteRenderer).setMaterial(material, 0);

            let singleStr = price.toString().substring(i, i + 1);
            resources.load("Sprites/Common/" + singleStr + "/spriteFrame", SpriteFrame, (err, spf: SpriteFrame) => {
                powerNd.getComponent(SpriteRenderer).spriteFrame = spf;
            });
        }
    }

    ShowFightCard() {//展示战斗卡牌
        let monsters = this.PlayerInit.children[0].getComponent(Player).HaveMonsters;
        let TargetPos = v3();
        let TargetAg = v3();
        this.scheduleOnce(() => {
            PlayerController.Instance.TakeOnTouch();
            Banner.Instance.ShowNativeAd();
        }, 2)
        if (monsters.length == 3) {
            for (let i in monsters) {
                resources.load("Prefabs/Card", Prefab, (err, pre) => {
                    let card = instantiate(pre);
                    card.getComponent(Card).Name = monsters[i].getComponent(Monster).Name;
                    card.setParent(this.MainCamera.getChildByName("FightCardInit"));
                    switch (i) {
                        case "0":
                            {
                                TargetPos = v3(-1, -0.1, -0.05);
                                TargetAg = v3(0, 0, 10);
                                card.getComponent(Card).CardPosed = TargetPos;
                                card.getComponent(Card).CardAngled = TargetAg;
                            }
                            break;
                        case "1":
                            {
                                TargetPos = Vec3.ZERO;
                                TargetAg = Vec3.ZERO;
                                card.getComponent(Card).CardPosed = TargetPos;
                                card.getComponent(Card).CardAngled = TargetAg;
                            }
                            break;
                        case "2":
                            {
                                TargetPos = v3(1, -0.1, 0.05);
                                TargetAg = v3(0, 0, -10);
                                card.getComponent(Card).CardPosed = TargetPos;
                                card.getComponent(Card).CardAngled = TargetAg;
                            }
                            break;
                    }
                    tween(card)
                        .to(2, { position: TargetPos, eulerAngles: TargetAg }, { easing: "quadOut" })
                        .start()
                })
            }
        }
        else {
            if (monsters.length == 4) {
                for (let i in monsters) {
                    resources.load("Prefabs/Card", Prefab, (err, pre) => {
                        let card = instantiate(pre);
                        card.getComponent(Card).Name = monsters[i].getComponent(Monster).Name;
                        card.setParent(this.MainCamera.getChildByName("FightCardInit"));
                        switch (i) {
                            case "0":
                                {
                                    TargetPos = v3(-1.5, -0.2, -0.05);
                                    TargetAg = v3(0, 0, 10);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "1":
                                {
                                    TargetPos = v3(-0.5, -0.1, -0.02);
                                    TargetAg = v3(0, 0, 3.5);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "2":
                                {
                                    TargetPos = v3(0.5, -0.1, 0.02);
                                    TargetAg = v3(0, 0, -3.5);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "3":
                                {
                                    TargetPos = v3(1.5, -0.2, 0.05);
                                    TargetAg = v3(0, 0, -10);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                        }
                        tween(card)
                            .to(2, { position: TargetPos, eulerAngles: TargetAg }, { easing: "quadOut" })
                            .start()
                    })
                }
            }
            else {
                for (let i in monsters) {
                    resources.load("Prefabs/Card", Prefab, (err, pre) => {
                        let card = instantiate(pre);
                        card.getComponent(Card).Name = monsters[i].getComponent(Monster).Name;
                        card.setParent(this.MainCamera.getChildByName("FightCardInit"));
                        switch (i) {
                            case "0":
                                {
                                    TargetPos = v3(-1.6, -0.2, -0.05);
                                    TargetAg = v3(0, 0, 10);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "1":
                                {
                                    TargetPos = v3(-0.8, -0.1, -0.025);
                                    TargetAg = v3(0, 0, 5);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "2":
                                {
                                    TargetPos = v3(0, 0, 0);
                                    TargetAg = v3(0, 0, 0);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "3":
                                {
                                    TargetPos = v3(0.8, -0.1, 0.025);
                                    TargetAg = v3(0, 0, -5);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                            case "4":
                                {
                                    TargetPos = v3(1.6, -0.2, 0.05);
                                    TargetAg = v3(0, 0, -10);
                                    card.getComponent(Card).CardPosed = TargetPos;
                                    card.getComponent(Card).CardAngled = TargetAg;
                                }
                                break;
                        }
                        tween(card)
                            .to(2, { position: TargetPos, eulerAngles: TargetAg }, { easing: "quadOut" })
                            .start()
                    })
                }
            }
        }
    }
}


